package org.wattdepot.cli.commands;

import java.util.ArrayList;
import java.util.List;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.client.BadXmlException;
import org.wattdepot.client.MiscClientException;
import org.wattdepot.client.NotAuthorizedException;
import org.wattdepot.client.ResourceNotFoundException;
import org.wattdepot.client.WattDepotClient;
import org.wattdepot.resource.source.jaxb.Source;
import org.wattdepot.util.tstamp.Tstamp;

/**
 * This class contains a command that generates the total power generated 
 * by all non-virtual sources associated with this source that use the specified fuel type.
 * It is used for one of the CommandLineInterface's actual commands.
 *  
 * @author David Mau
 */
public class TotalPowerCommand implements WattDepotCliCommand {
  // Default client-server connection to use unless given one.
  private WattDepotClient client = new WattDepotClient(debug);

  /**
   * This constructor makes sure that the client really is connected to the server.
   * 
   * @param anotherClient Specifies if the user wants to use another WattDepot server
   * other than the default simulation one.
   */
  public TotalPowerCommand( String anotherClient ) {
    // If another client is provided
    if ( anotherClient != null ) {
      client = new WattDepotClient( anotherClient );
    }
    
    // Stop right away if we cannot contact server.
    if (!client.isHealthy()) {
      System.out.println("Failed to connect to " + client.getWattDepotUri());
      return;
    }
    // Indicate successful connection.
    //System.out.println("Connected to " + client.getWattDepotUri());
  }
  
  /**
   * The method returns a table in String form that lists the fuel types and
   * the non-virtual sources that generate power using that type.
   * Created by David Mau.
   * 
   * @param args A list of arguments given to this command
   * @return A String with the fuel types command output in it.
   */
  public String doCommand(List<String> args) {
    String output = "";
    // Check the size of the arguments passed to this command.
    // If the number of arguments is too large or too small,
    // return an error.
    if (args.size() > 3) {
      output = tooManyArguments;
      output = output.concat(cr);
      return output;
    }
    if (args.size() < 3) {
      output = missingArguments;
      output = output.concat(cr);
      return output;
    }
    
    String sourceName = args.get(0);
    String timeStamp = args.get(1);
    String fuelType = args.get(2);
    
    XMLGregorianCalendar xmlTimeStamp = null;
    // Convert the String time stamp into an XML one.
    try {
      xmlTimeStamp = Tstamp.makeTimestamp(timeStamp);
    }
    catch (Exception e) {
      output = badTimeStamp;
      output = output.concat(e.toString());
      output = output.concat(cr);
      return output;
    }
    
    // Create a list for all of the sources that the program will need to go through.
    ArrayList<Source> allSources = new ArrayList<Source>();
    
    // Place all non-virtual sources that the parent source links to into the list.
    try {
      // Get the source information from the client using the argument passed.
      Source parent = client.getSource( sourceName );
      
      // Add the source to the list of fuel sources the program needs to go through.
      allSources.add( parent );
      
      int counter = 0;
        
      // Go through the list of uncheckedSources
      while ( counter < allSources.size() ) {
        
        // If the source is a virtual source,
        if ( allSources.get(counter).isVirtual() ) {
          
          // Get all sub-sources from the parent.
          List<String> children = allSources.get(counter).getSubSources().getHref();
          // Add them all as sources to the list.
          for ( String child : children ) {
            
            // Break the url up.
            String[] urlBreak = child.split("/");
            ArrayList<String> brokenUrl = new ArrayList<String>();
            for ( String url : urlBreak ) {
              brokenUrl.add( url );
            }
            // Figure out the last part of the url.
            int lastIndex = brokenUrl.size() - 1;
            
            // Get the source from the client.
            Source newAddition = client.getSource( brokenUrl.get(lastIndex) );
            // Add the child to the list.
            allSources.add(newAddition);
          }
          
          // Remove the virtual source from the list
          allSources.remove(counter);
        }
        // Otherwise, the source is non-virtual.
        else {
          // Move onto the next item on the list.
          counter++;
        }
      }
      
      // Go through all of the sources and remove the ones that don't have the given
      // fuel type in the arguments.
      counter = 0;
      while ( counter < allSources.size() ) {
        // If the fuelType of the source does match,
        if ( fuelType.compareTo( allSources.get(counter).getProperty("fuelType")) == 0 ) {
          // Go onto the next source
          counter++;
        }
        else {
          // Otherwise, remove the source from the list
          allSources.remove(counter);
        }
      }
      
      // If the fuelType given hasn't been found in the sources,
      if ( allSources.isEmpty() ) {
        // Return an error.
        output = fuelTypeNotFound;
        output = output.concat(cr);
        return output;
      }
      
      double doubleOutput = 0;
      // For each source in the list that uses the fuelType,
      for ( Source source : allSources ) {
        doubleOutput += client.getPowerGenerated( source.getName(), xmlTimeStamp );
      }
      
      // Turn the Watts into MegaWatts
      doubleOutput = doubleOutput / 1000000;
      
      // Convert the double into a string for the output.
      output = String.valueOf( doubleOutput );
      output = output.concat( " MegaWatts" );
      output = output.concat(cr);
      
      // Return the result.
      return output;
    }
    catch (NotAuthorizedException e) {
      output = notAuthorized;
      output = output.concat(e.toString());
      output = output.concat(cr);
      return output;
    }
    catch (ResourceNotFoundException e) {
      output = resourceNotFound;
      output = output.concat(e.toString());
      output = output.concat(cr);
      return output;
    }
    catch (BadXmlException e) {
      output = badXml;
      output = output.concat(e.toString());
      output = output.concat(cr);
      return output;
    }
    catch (MiscClientException e) {
      output = miscClient;
      output = output.concat(e.toString());
      output = output.concat(cr);
      return output;
    }
  }
}
